<template>
  <div ref="slotRoot" select-none
    flex items-center
    h="2rem" 槽>

    <div @dblclick="toggleShowInput" 前置标题 v-if="slot.prototype.direction === 'out'" mr1>{{ slot.prototype.title }}</div>

    <div 主体
      @click.stop="onClick"
      @dblclick.stop="onDbclick"
      @mousedown.stop="">
      <img 图标 v-if="isProcess && isConnected" block select-none style="-webkit-user-drag: none;" w="16px" h="12px" src="~/assets/blueprint-process-o.svg" alt="">
      <img 图标 v-else-if="isProcess && !isConnected" w="16px" block select-none style="-webkit-user-drag: none;" h="12px" src="~/assets/blueprint-process.svg" alt="">
      <div v-else-if="isData && showInput" w="5rem">
        <VarInput :varlike="slot"/>
      </div>
      <div 图标 v-else-if="isData && !isConnected" class="dot" w3 h3 b-rd-1.5></div>
      <div 图标 v-else-if="isData && isConnected" w3 h3 b-rd-1.5 style="background: var(--bg-content);"></div>
    </div>

    <div @dblclick="toggleShowInput" 后置标题 v-if="slot.prototype.direction === 'in'" ml1>{{ slot.prototype.title }}</div>

    
  </div>
</template>

<script setup lang="ts">
import { MathPoint } from '~/models/Math/MathPoint';
import { tAny, TypesInherent, TypesReceiveLiterial } from '~/models/types';
import { oBus } from '~/models/graph/editorbus';
import { oGraph } from '~/models/graph/graph';
import type { ISlot } from '~/models/graph/slot/instance';
import { PSlotType } from "~/models/graph/slot/type";
import { TypeTemplate } from '~/models/types/type_template';
import { GetAllBundles } from '~/models/pyBundles';
import { oProject, oStorage } from '~/models/Project';
import type { DataType } from '~/models/types/type';
import { explicitTypeOf, typeOfValue } from '~/models/types/utils';
import { Value } from '~/models/value/Value';

const props = defineProps<{
  slot: ISlot
}>()
const emits = defineEmits<{
  (e: 'update:slot', event: ISlot): void,
}>()

const slotRoot = ref(null as null | HTMLElement)
const centerPoint = ref(new MathPoint())

function anounceUpper(inner: DataType, symbol: string) {
  // 通知节点
  const parentNode = oStorage.value?.nodes.find(node => node.slotsId.includes(props.slot.id))
  if (!parentNode) {
    throw new Error('找不到parentNode')
  }
  else {
    console.log(`节点<${parentNode.prototype.title}>泛型模板更新`);
  }
  const parentT = parentNode.typeTemplates.find(x => x.symbol === symbol)
  if (!parentT) {
    console.error('parentNode', parentNode)
    console.error('(props.slot.prototype.dataType as TypeTemplate).symbol', symbol)
    throw new Error('找不到parentNode上的类型模板')
  }
  parentT.mountType = inner

  // 通知节点上的其他使用了同一个模板的插槽
  const slotsUsingSameT = parentNode.slots.filter(slot => slot.usingTemplate)
  slotsUsingSameT.forEach(slot => {
    slot.updateTDirect(inner)
    console.log(`槽{${slot.prototype.title}}updateTDirect: ${inner.name}`);
  })
}

function changeTemplate(t: DataType) {
  if (props.slot.usingTemplate) {
    const { type: inner, symbol } = props.slot.updateTCompare(t)
    console.log(`对比更新<${symbol}>: Receive(${t.name}) -> Inner(${inner.name})`);
    
    anounceUpper(inner, symbol)
  }
  // else {
  //   console.error('?????????????');
  //   console.error(props.slot.prototype.dataType)
  // }
}

function tryClearTemplate() {
  console.log('tryClearTemplate');
  
  // 通知节点
  const parentNode = oStorage.value?.nodes.find(node => node.slotsId.includes(props.slot.id))
  if (!parentNode) {
    throw new Error('找不到parentNode')
  }
  console.log('parentNode', parentNode);
  console.log('slot', props.slot);

  const symbols = props.slot.symbolsInUsing


  /** 对每个使用的符号分别判断 */
  for (const symbol of symbols) {
    console.log(`对于<${symbol}>`);
    
    const parentT = parentNode.typeTemplates.find(x => x.symbol === symbol)
    if (!parentT) {
      throw new Error(`找不到parentNode上的类型模板<${symbol}>`)
    }

    // 通知节点上的其他使用了同一个模板的插槽
    const slotsUsingSameT = parentNode.slots.filter(slot => {
      return slot.usingTemplate && slot.symbolsInUsing.includes(symbol)
    })

    // 如果所有应用了相同模板的插槽都没有在使用，那么就进行挂载类型清空

    const allUnused = slotsUsingSameT.every(slot => !slot.inUse)

    if (allUnused) {
      console.log(`没有任何插槽继续使用<${symbol}>`);
      console.log('slotsUsingSameT', slotsUsingSameT);
      
      parentT.mountType = tAny
      slotsUsingSameT.forEach(slot => {
        (slot.prototype.dataType as TypeTemplate).mountType = tAny
      })
    }
  }
  
  
}

watch(() => props.slot.data, () => {
  console.log(`槽${props.slot.prototype.name}数据变化`);
  if (props.slot.usingTemplate) {
    if (props.slot.data !== undefined) {
      console.log(`槽${props.slot.prototype.name}泛型模板更新`);
      changeTemplate(typeOfValue(props.slot.data))
    }
    else {
      tryClearTemplate()
    }
  }
})
watch(() => props.slot._peersId, () => {
  // console.log(`槽{${props.slot.prototype.title}}连接状态变化`);
  if (props.slot.usingTemplate) {
    // console.log('props.slot.peer', props.slot.peer);
    if (props.slot.peer) {
      console.log(`从槽{${props.slot.prototype.title}}开始泛型模板更新`);
      if (props.slot.peer.prototype.dataType!.is(tAny)) {
        return
      }
      else {
        changeTemplate(explicitTypeOf(props.slot.peer.prototype.dataType!))
      }
    }
    else {
      tryClearTemplate()
    }
  }
}, { deep: true })


function onClick(ev: MouseEvent) {
  oBus.value.slotClicked(props.slot, centerPoint.value)
}

const isProcess = computed(() => {
  return props.slot.prototype.type === PSlotType.Process
})
const isData = computed(() => {
  return props.slot.prototype.type === PSlotType.Data
})
const isIn = computed(() => {
  return props.slot.prototype.direction === 'in'
})
const isOut = computed(() => {
  return props.slot.prototype.direction === 'out'
})
const isConnected = computed(() => {
  return props.slot.peer
})



function onDbclick() {

  // 双击: 如果连接了就取消连接
  if (props.slot.peer) {
    props.slot.disconnect()
    emits('update:slot', props.slot)
  }
  // 如果本俩就没连接，打开常量输入
  else {
    toggleShowInput()
  }
}


/**
 * 关于自动写XY
 */

function writeXY() {
  const r = slotRoot.value?.getBoundingClientRect()!
  centerPoint.value.x = r.x + r.width/2
  centerPoint.value.y = r.y + r.height/2
  props.slot.x = centerPoint.value.x
  props.slot.y = centerPoint.value.y
}

const observer = ref(new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    writeXY()
  });
}))

onMounted(() => {
  writeXY()

  const config = { attributes: true, childList: true, subtree: true }

  
  let p = slotRoot.value!.parentNode
  while (!(p as Element).classList.contains('node-display')) {
    p = p?.parentNode!
  }
  if (p) {
    observer.value.observe(p, config)
  }
})

onUnmounted(() => {
  observer.value.disconnect()
})

/**
 * 关于自动写XY：结束
 */


/**
 * 关于常量输入
 */

const showInput = computed(() => props.slot.data !== undefined)

function toggleShowInput() {
  if (
    !props.slot.prototype.dataType
    || props.slot.prototype.direction === 'out'
  ) {
    console.log(props.slot.prototype);
    
    return
  }

  if (showInput.value) {
    delete props.slot.data
  }
  else {
    props.slot.disconnect()
    // 设置了缺省值，就恢复缺省值。否则就用类型默认值
    props.slot.data = props.slot.prototype.defaultValue ?? Value.default(props.slot.prototype.dataType)
  }
}
</script>